<template>
  <view class="compress">
    <canvas canvas-id="compress_canvas" :style="{ width: `${width}px`, height: `${height}px` }"></canvas>
  </view>
</template>

<script>
import base64ToPath from './base64ToPath.js'

const CANVAS_ID = 'compress_canvas'

function sleep(time) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, time)
  })
}

function calcImageSize(res, maxWidth) {
  let imgW = res.width
  let imgH = res.height

  let scale = 1

  if (imgW > maxWidth) {
    scale = imgW / maxWidth
    imgW = maxWidth
    imgH = Math.floor(imgH / scale)
  }

  if (imgH > maxWidth) {
    scale = imgH / maxWidth
    imgH = maxWidth
    imgW = Math.floor(imgW / scale)
  }

  return {
    imgW,
    imgH
  }
}

function canvasToFile({ canvasId = CANVAS_ID, width, height, type, quality }) {
  return new Promise((resolve, reject) => {
    uni.canvasToTempFilePath({
      canvasId,
      x: 0,
      y: 0,
      width,
      height,
      destWidth: width,
      destHeight: height,
      fileType: type,
      quality,
      success: resolve,
      fail: reject
    }, this)
  })
}

function urlTobase64(url, type) {
  return new Promise((resolve, reject) => {
    uni.getFileSystemManager().readFile({
      filePath: url,
      encoding: 'base64',
      success: res => {
        let base64 = res.data
        base64 = `data:image/${type};base64,${base64}`
        resolve(base64)
      },
      fail: reject
    })
  })
}
export default {
  name: 'Compress',

  data() {
    return {
      width: 0,
      height: 0
    }
  },
  mounted() {
    this.$emit('imageMounted')
  },
  methods: {
    compress(imgUrl, options = {}) {
      /** ************* 参数默认值 */
      const MAX_SIZE = 1024 // 最大分辨率，宽 * 高 的值
      const MAX_QUALITY = 0.92 // 压缩质量
      const IMG_TYPE = 'jpg' // png | jpg
      const BASE_64 = false

      return new Promise((resolve, reject) => {
        uni.getImageInfo({
          src: imgUrl,
          success: async res => {
            if (!res) return reject(new Error('获取图片信息异常'))

            const quality = options.quality || MAX_QUALITY
            const type = options.type || IMG_TYPE
            const isBase64 = options.base64 || BASE_64
            const minSize = options.minSize || 640
            const maxSize = options.maxSize || MAX_SIZE

            const { imgW, imgH } = calcImageSize(res, maxSize)
            const width = options.width || imgW
            const height = options.height || imgH

            if (width <= minSize && height <= minSize) {
              resolve(imgUrl)
              return
            }

            this.height = height
            this.width = width
            await sleep(300)
            const canvas = uni.createCanvasContext(CANVAS_ID, this)
            canvas.clearRect(0, 0, width, height)
            canvas.drawImage(res.path, 0, 0, width, height)
            canvas.draw(false, async () => {
              await sleep(30)
              const file = await canvasToFile({ width, height, type, quality })
              try {
                if (isBase64) {
                  // #ifdef H5
                  resolve(file.tempFilePath)
                  // #endif
                  // #ifndef H5
                  resolve(await urlTobase64(file.tempFilePath, type))
                  // #endif
                } else {
                  // #ifdef H5
                  const path = await base64ToPath(file.tempFilePath)
                  // 在H5平台下，tempFilePath 为 base64
                  window.URL.revokeObjectURL(file.tempFilePath)
                  resolve(path)
                  // #endif
                  // #ifndef H5
                  resolve(file.tempFilePath)
                  // #endif
                }
              } catch (e) {
                reject(e)
              }
            })
          },
          fail: reject
        })
      })
    },
    async start(imgUrl, options = {}) {
      if (Array.isArray(imgUrl)) {
        const temp = []
        for (let i = 0; i < imgUrl.length; i++) {
          const item = imgUrl[i]
          try {
            const tempPath = await this.compress(item, options)
            temp.push(tempPath)
          } catch (e) {
            temp.push(item)
          }
        }
        return temp
        /* 不能同时并行压缩，需要串行 */
        // Promise.all(imgUrl.map((item) => this.compress(item, options))).then(resolve).catch(reject)
      } else {
        return this.compress(imgUrl, options)
      }
    },
    /**
     * @description 选择图片并压缩，参数同uni.chooseImage api
     * @param {object} chooseImageConfig
     * @param {object} compressImgConfig
     */
    chooseImageCompressed(chooseImageConfig = {}, compressImgConfig = {}) {
      chooseImageConfig = Object.assign({
        count: 1, // 默认图片张数
        sizeType: ['original'], // 可以指定是原图还是压缩图，默认二者都有 , 'compressed'
        sourceType: ['album', 'camera'] // 从相册选择
      }, chooseImageConfig)

      return new Promise((resolve, reject) => {
        uni.chooseImage({
          ...chooseImageConfig,
          success: (res) => {
            const tempFilePaths = res.tempFilePaths
            let tempPath = tempFilePaths
            if (tempFilePaths.length === 1) tempPath = tempFilePaths[0]
            this.start(tempPath, compressImgConfig).then(resolve).catch(reject)
          },
          fail: reject
        })
      })
    }
  }
}
</script>

<style scoped>
.compress {
  position: absolute;
  left: 10000px;
  visibility: hidden;
  height: 0;
  overflow: hidden;
}
</style>
